/*
 * Created by IntelliJ IDEA.
 * User: rousseau
 * Date: May 12, 2002
 * Time: 3:14:55 PM
 * To change template for new class use
 * Code Style | Class Templates options (Tools | IDE Options).
 */
package org.jfract.abstractBeans;

import java.io.Serializable;
import java.util.Vector;

import org.jfract.util.CompletionListener;
import org.jfract.util.FractalColorComputer;
import org.jfract.util.Location;
import org.jfract.util.PictureColorProcessor;

import android.graphics.Bitmap;
import android.graphics.Color;

/**
 * this is an abstract class for the beans that implements FractalComputer.
 */
public abstract class AbstractFractalColorBean
    implements Serializable, FractalColorComputer
{
  protected PictureColorProcessor processor;

  public String expression = "Z^2 + C";

  // protected org.nfunk.jep.JEP parser;

  /**
   * Compute the result for a point in x,y
   */
  public int computeFractal(double x, double y)
  {
    return computer.computeFractal(x, y);
  }

  /**
   * get the processor to manage it
   * 
   * @return
   */
  public PictureColorProcessor getProcessor()
  {
    return processor;
  }

  /** pause the picture processor */
  public void pause()
  {
    if (processor != null)
      processor.pause();
  }

  /** stop the picture processor */
  public void stop()
  {
    if (processor != null)
      processor.stopThread();
  }

  public void resume()
  {
    if (processor != null)
      processor.notifyThread();
  }

  /**
   * give the default location in term of x, y, zoom
   */
  public Location getDefaultLocation()
  {
    return computer.getDefaultLocation();
  }

  public FractalColorComputer getComputer()
  {
    return computer;
  }

  public void setComputer(FractalColorComputer computer)
  {
    this.computer = computer;
  }

  private FractalColorComputer computer = (FractalColorComputer) this;

  public void setLocation(Location location)
  {
    this.location = location;
  }

  public Location getLocation()
  {
    return location;
  }

  private Location location = this.getDefaultLocation();

  public double getZoomFactor()
  {
    return zoomFactor;
  }

  public void setZoomFactor(double zoomFactor)
  {
    this.zoomFactor = zoomFactor;
  }

  private double zoomFactor = 2;

  public void setCompletion(CompletionListener completion)
  {
    this.completion = completion;
  }

  private transient CompletionListener completion;

  public double getXmin()
  {
    return xmin;
  }

  public double getYmin()
  {
    return ymin;
  }

  public double getDeltay()
  {
    return deltay;
  }

  public double getDeltax()
  {
    return deltax;
  }

  /**
   * The buffered image to paint the graphics
   */
  private transient Bitmap img = null;

  public void setIter(int iter)
  {
    this.iter = iter;
  }

  /**
   * the zoom
   */
  private double zoom = .5;

  public int getIter()
  {
    return iter;
  }

  protected int iter = 255;

  protected int[] color;

  public int[] getColor()
  {
    return color;
  }

  public void setColor(int[] color)
  {
    this.color = color;
  }

  public int[] getInternColor()
  {
    return internColor;
  }

  public Vector getInternColorVector()
  {
    return internColorVector;
  }

  public void setInternColor(int[] internColor)
  {
    this.internColor = internColor;
    internColorVector.clear();
    for (int i = 0; i < internColor.length; i++)
    {
      int color = internColor[i];
      internColorVector.add(color);
    }
  }

  protected int internColor[] = COLORBLACK_TO_RED;

  protected Vector internColorVector = new Vector();

  /**
   * The red color palette
   */
  protected static int[] COLORRED;

  /**
   * The green color palette
   */
  protected static int[] COLORGREEN;

  /**
   * inverted palette
   */
  public static int[] COLORWHITE;

  public static int[] COLORWHITEBRUT;

  public static int[] COLORBLACK_TO_RED;

  /**
   * The deltax value representing the incrementation of x value for a diff of one pixel
   */
  private double deltax;

  /**
   * same as delatx for y axe
   */
  private double deltay;

  /**
   * the extreme left x value of the graph
   */
  private double xmin;

  /**
   * same for y axes
   */
  private double ymin;

  /**
   * static bloc to build the colors
   */
  static
  {
    COLORRED = new int[100];
    COLORGREEN = new int[100];
    for (int i = 0; i < 99; i++)
    {
      COLORRED[i] = Color.rgb(i, 0, 0);
    }
    COLORRED[99] = Color.rgb(0, 0, 255);

    for (int i = 0; i < 99; i++)
    {
      COLORGREEN[99] = Color.rgb(0, i, 0);
    }
    COLORGREEN[99] = Color.rgb(0, 0, 255);
    COLORWHITE = new int[256];
    for (int i = 0; i < 255; i++)
    {
      COLORWHITE[i] = Color.rgb(255 - i, 255 - i, 255);
    }
    COLORWHITE[255] = Color.rgb(0, 0, 255);
    COLORWHITEBRUT = new int[256];
    for (int i = 0; i < 45; i++)
    {
      COLORWHITEBRUT[i] = Color.rgb(255 - 4 * i, 255 - 4 * i, 255);
    }
    for (int i = 45; i < 255; i++)
    {
      COLORWHITEBRUT[i] = Color.rgb(0, 0, 255);
    }
    COLORWHITEBRUT[255] = Color.rgb(0, 0, 255);
    COLORBLACK_TO_RED = new int[256];
    for (int i = 0; i < 256; i++)
    {
      COLORBLACK_TO_RED[i] = Color.rgb(i, 0, 0);
    }
  }

  /**
   * The constructor
   */
  public AbstractFractalColorBean()
  {
    // completion = new CompletionListener()
    // {
    // int currentMax;
    // public void completionEventPerformed (int step, int max)
    // {
    // if (max != currentMax)
    // {
    // //bar.setMaximum(max);
    // currentMax = max;
    // }
    // //bar.setValue(step);
    // }
    // };
    setLocation(getDefaultLocation());
    // jBeanable.addPropertyChangeListener(new PropertyChangeListener()
    // {
    // /**
    // * This method gets called when a bound property is changed.
    // * @param evt A PropertyChangeEvent object describing the event source
    // * and the property that has changed.
    // */
    //
    // public void propertyChange(PropertyChangeEvent evt)
    // {
    // //System.out.println("propertylistener called " + evt + " " + evt.getPropertyName() + " " + evt.getOldValue() + "/" + evt.getNewValue());
    // }
    // });

  }

  /**
   * rebuild the JBeanable fr deserialization
   */
  // public void rebuildJBeanable()
  // {
  // try
  // {
  // jBeanable = JBeanFactory.getJbeanableImpl(this);
  // }
  // catch (WrongBeanException e)
  // {
  // }
  // }

  // public void rebuildCompletion ()
  // {
  // completion = new CompletionListener()
  // {
  // int currentMax;
  // public void completionEventPerformed (int step, int max)
  // {
  // if (max != currentMax)
  // {
  // if (bar != null)
  // {
  // bar.setMaximum(max);
  // currentMax = max;
  // }
  // }
  //
  // if (bar != null)
  // {
  // bar.setValue(step);
  // }
  // }
  // };
  // }

  /**
   * Create the image
   */
  private void createImg()
  {
    // Dimension dim = jBeanable.getJBean().getPanelBean().getSize ();
    // img = new BufferedImage (Math.max (jBeanable.getJBean().getPanelBean().getWidth(),1),Math.max
    // (jBeanable.getJBean().getPanelBean().getHeight(),1),BufferedImage.TYPE_INT_RGB);
    // img = new Bitmap();
    // gfx = img.createGraphics();
  }

  /**
   * set the color table
   */
  public void setPalette(int[] color)
  {
    this.color = color;
    // System.out.println("setColor " + this.color);
  }

  // public void initComponant()
  // {
  // bar = new JProgressBar();
  // bar.setStringPainted(true);
  //
  // jBeanable.getJBean().getPanelBeanContainer().setLayout(new BorderLayout());
  // JButton refreshButton = new JButton(JFractGui.bundle.getString("button_refresh"));
  // refreshButton.addActionListener (new ActionListener()
  // {
  // /**
  // * Invoked when an action occurs.
  // */
  // public void actionPerformed(ActionEvent e)
  // {
  // updateImg();
  // jBeanable.getJBean().getPanelBean().repaint();
  // }
  // }
  // );
  // JButton killButton = new JButton(new ImageIcon (getClass().getClassLoader().getResource("toolbarButtonGraphics/media/Stop24.gif") ));
  // killButton.addActionListener (new ActionListener()
  // {
  // /**
  // * Invoked when an action occurs.
  // */
  // public void actionPerformed(ActionEvent e)
  // {
  // processor.interrupt();
  // completion.completionEventPerformed(0,0);
  // }
  // }
  // );
  //
  // JButton defaultButton = new JButton(JFractGui.bundle.getString("button_default"));
  // defaultButton.addActionListener (new ActionListener()
  // {
  // /**
  // * Invoked when an action occurs.
  // */
  // public void actionPerformed(ActionEvent e)
  // {
  // setLocation(getDefaultLocation());
  // updateImg();
  // jBeanable.getJBean().getPanelBean().repaint();
  // }
  // }
  // );
  // JPanel command_pane = new JPanel();
  // command_pane.setLayout(new BorderLayout());
  // command_pane.add(refreshButton, BorderLayout.CENTER);
  // command_pane.add(defaultButton, BorderLayout.EAST);
  // command_pane.add(killButton, BorderLayout.WEST);
  // command_pane.add(bar, BorderLayout.NORTH);
  //
  // jBeanable.getJBean().getPanelBeanContainer().add(command_pane, BorderLayout.SOUTH);
  // jBeanable.getJBean().getPanelBeanContainer().add(jBeanable.getJBean().getPanelBean(), BorderLayout.CENTER);
  // }

  // /**
  // * paint the graphics
  // */
  // public void drawBean(Graphics g)
  // {
  // if (img == null)
  // {
  // createImg();
  // //updateImg();
  // }
  // g.drawImage
  // (img,0,0,jBeanable.getJBean().getPanelBean().getWidth(),jBeanable.getJBean().getPanelBean().getHeight(),jBeanable.getJBean().getPanelBean());
  // }

  /**
   * re paint the pics when it is resized
   */
  public void reDrawBean()
  {
    // createImg();
    // updateImg();
  }

  /**
   * The method used to compute the deltax and deltay as double used to draw the graphics
   */
  public void computeDelta(int width, int height)
  {
    double current_x = getLocation().x;
    double current_y = getLocation().y;
    double current_zoom = getLocation().zoom;

    deltax = 1 / (current_zoom * width);
    deltay = 1 / (current_zoom * height);
    xmin = current_x - ((double) .5 * (1 / current_zoom));
    ymin = current_y - ((double) .5 * (1 / current_zoom));
  }

  public void updateImg()
  {
    createImg();
    processor = new PictureColorProcessor(this, img, completion, true);
    processor.start();
  }

  // /**
  // * Invoked when the mouse has been clicked on a component.
  // */
  // public void mouseClicked(MouseEvent e)
  // {
  // }
  //
  // /**
  // * Invoked when a mouse button has been pressed on a component.
  // */
  // public void mousePressed(MouseEvent e)
  // {
  //
  // double current_x = getLocation().x;
  // double current_y = getLocation().y;
  // double current_zoom = getLocation().zoom;
  // double current_zoom_factor = getZoomFactor();
  // int xloc = e.getX();
  // int yloc = e.getY();
  //
  // double newX1I = new Double(xloc).doubleValue();
  // double newY1I = new Double(yloc).doubleValue();
  //
  // double newX1 = current_x - (double).5*(1/current_zoom) + (newX1I/current_zoom)/jBeanable.getJBean().getPanelBean().getSize().width;
  // double newY1 = current_y + (double).5*(1/current_zoom) - (newY1I/current_zoom)/jBeanable.getJBean().getPanelBean().getSize().height;
  //
  // if (e.getModifiers()== MouseEvent.BUTTON1_MASK)
  // setLocation(new Location(newX1, newY1, current_zoom*current_zoom_factor));
  // if (e.getModifiers()== MouseEvent.BUTTON3_MASK)
  // setLocation(new Location(newX1, newY1, current_zoom/current_zoom_factor));
  //
  // updateImg();
  // //jBeanable.getParent().repaint();
  // }
  //
  // /**
  // * Invoked when a mouse button has been released on a component.
  // */
  // public void mouseReleased(MouseEvent e)
  // {
  // }
  //
  // /**
  // * Invoked when the mouse enters a component.
  // */
  // public void mouseEntered(MouseEvent e)
  // {
  // //setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
  // }
  //
  // /**
  // * Invoked when the mouse exits a component.
  // */
  // public void mouseExited(MouseEvent e)
  // {
  // }

  // todo serialization xml
  // private void writeObject(java.io.ObjectOutputStream out)
  // throws IOException
  // {
  // out.writeObject(computer);
  // out.writeObject(location);
  // out.writeObject(color);
  // out.writeObject(new Integer(iter));
  // }
  //
  // private void readObject(java.io.ObjectInputStream in)
  // throws IOException, ClassNotFoundException
  // {
  // FractalColorComputer computer = (FractalColorComputer)in.readObject();
  // setComputer(computer);
  // rebuildJBeanable();
  // rebuildCompletion();
  // setLocation((Location)in.readObject());
  // setColor((Color[])in.readObject());
  // setIter( ((Integer)in.readObject()).intValue() ) ;
  // createImg ();
  // }

  public String getExpression()
  {
    return expression;
  }

  public void setExpression(String expression)
      throws IllegalArgumentException
  {
    // parser = new org.nfunk.jep.JEP();
    // parser.addStandardFunctions();
    // parser.addStandardConstants();
    // parser.addComplex();
    // parser.addComplexVariable("Z", 0, 0);
    // parser.addComplexVariable("C", 0, 0);
    // parser.parseExpression(expression);
    // if( parser.hasError())
    // {
    // if (JFractGui.isInstanced()) {
    // JFractGui.showMessage("Error", parser.getErrorInfo());
    // }
    // else
    // {
    // throw new IlñlegalArgumentException(parser.getErrorInfo());
    // }
    // }
    // else
    // {
    this.expression = expression;
    // }
  }

}
